#!/usr/bin/env python3

# Import the core classes from the siliconcompiler library.
from siliconcompiler import ASIC, Design
# Import a pre-defined target for the FreePDK45 process.
from siliconcompiler.targets import freepdk45_demo
# Import the base ASIC flow to customize it.
from siliconcompiler.flows.asicflow import ASICFlow
# Import the specific tool task for compiling Bluespec.
from siliconcompiler.tools.bluespec import convert


def main():
    '''
    This script demonstrates a Bluespec SystemVerilog (BSV) to GDSII flow.
    It shows how to create a custom compilation flow in SiliconCompiler
    to handle high-level synthesis from BSV before proceeding with the
    standard synthesis, place, and route steps.
    '''

    # --- Design Setup ---
    # Create a design schema to hold the project's configuration.
    design = Design("fibone")
    # Set up a 'dataroot' to easily reference local files.
    design.set_dataroot("fibone", __file__)

    # Configure the "rtl" fileset.
    # Note that the source file is a '.bsv' file, not Verilog.
    with design.active_dataroot("fibone"), design.active_fileset("rtl"):
        # The topmodule 'mkFibOne' is the name of the compiled module
        # generated by the Bluespec compiler, not the file name.
        design.set_topmodule("mkFibOne")
        design.add_file("FibOne.bsv")

    # --- Project Setup ---
    # Create a standard ASIC project.
    project = ASIC(design)

    # Tell the project to use the "rtl" fileset we defined.
    project.add_fileset("rtl")

    # Load the target configuration for the FreePDK45 technology.
    freepdk45_demo(project)

    # --- Custom Flow Definition ---
    # This is the key part of the example. We will modify the standard
    # ASIC flow to include a Bluespec compilation step.

    # 1. Start with a copy of the standard ASIC flow.
    flow = ASICFlow("asic-bluespec")

    # 2. The standard flow has an 'elaborate' step for SystemVerilog that is
    #    not needed, as the Bluespec compiler handles elaboration. Remove it.
    flow.remove_node("elaborate")

    # 3. Add a new step (node) to the flow graph named "convert".
    #    This step will run the Bluespec compiler (bsc) to convert the
    #    .bsv source into Verilog.
    flow.node("convert", convert.ConvertTask())

    # 4. Modify the flow graph's connections (edges). Reroute the flow so
    #    that the output of our new "convert" step feeds into the "synthesis" step.
    flow.edge("convert", "synthesis")

    # 5. Apply this new, custom flow to our project.
    project.set_flow(flow)

    # --- Execution & Analysis ---
    # Run the custom flow. SiliconCompiler will now execute the 'convert'
    # step first, then proceed to synthesis, place, route, etc.
    project.run()

    # Display a summary of the results (timing, area, etc.).
    project.summary()

    return project


if __name__ == '__main__':
    main()
